#include "st7735.h"
#include <string.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
// #include "esp_spi_bus.h"
#include "esp_lcd_panel_st7789.h"
#include "esp_lcd_panel_interface.h"
#include "esp_lcd_panel_ops.h"
// #include "driver/gpio.h"
#include "esp_timer.h"
#include "jpeg_decoder.h"
#include "sntp_time.h"

static const char *TAG = "ST7735";

#define LV_USE_ANTIALIAS 1
LV_FONT_DECLARE(font_puhui_14_1);
// LV_FONT_DECLARE(font_awesome_14_1);


// GPIO 初始化
// void gpio_init() {
//     ESP_LOGI(TAG, "Initializing GPIO pins...");

//     gpio_reset_pin(ST7735_CK_GPIO);
//     gpio_reset_pin(ST7735_MOSI_GPIO);
//     gpio_reset_pin(ST7735_RST_GPIO);
//     gpio_reset_pin(ST7735_DC_GPIO);
//     gpio_reset_pin(ST7735_CS_GPIO);
//     gpio_reset_pin(ST7735_BLK_GPIO);

//     gpio_set_direction(ST7735_CK_GPIO, GPIO_MODE_OUTPUT);
//     gpio_set_direction(ST7735_MOSI_GPIO, GPIO_MODE_OUTPUT);
//     gpio_set_direction(ST7735_RST_GPIO, GPIO_MODE_OUTPUT);
//     gpio_set_direction(ST7735_DC_GPIO, GPIO_MODE_OUTPUT);
//     gpio_set_direction(ST7735_CS_GPIO, GPIO_MODE_OUTPUT);
//     gpio_set_direction(ST7735_BLK_GPIO, GPIO_MODE_OUTPUT);

//     gpio_set_level(ST7735_BLK_GPIO, 1); // BLK 高电平点亮背光

//     ESP_LOGI("DISPLAY", "GPIO initialized.");
// }

size_t decoded_size = ST7735_HEIGHT * ST7735_WIDTH * sizeof(uint16_t);
uint16_t rgb565_buffer[ST7735_HEIGHT * ST7735_WIDTH * sizeof(uint16_t)];

#define BUF_HEIGHT 20  // lvgl局部缓冲区高度
static lv_display_t *disp;
static esp_lcd_panel_handle_t panel_handle;
static lv_obj_t *img=NULL;
static lv_image_dsc_t img_dsc;
lv_obj_t *label_date,*label_time,*label_week;
bool needRenderPhoto=false;

// LVGL display flush callback
void lvgl_flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *color_p) {
    // ESP_LOGI(TAG,"inflush......................................");
    int32_t w = (area->x2 - area->x1 + 1);
    int32_t h = (area->y2 - area->y1 + 1);
    int32_t len = w * h *2;
    /*
    for (int i = 0; i < len; i+=2) {
        uint8_t c = color_p[i];
        color_p[i]=color_p[i+1];
        color_p[+1] = c;
    }
    */
    lv_draw_sw_rgb565_swap(color_p,len);
    esp_lcd_panel_draw_bitmap(panel_handle, 
        area->x1, area->y1, area->x2+1, area->y2+1, 
        color_p);
    lv_display_flush_ready(disp);
 }

// esp panel SPI 初始化
void initializeSpi() {
    ESP_LOGI("DISPLAY", "Initializing SPI bus...");
    spi_bus_config_t buscfg = {};
    buscfg.mosi_io_num = ST7735_MOSI_GPIO;
    buscfg.miso_io_num = GPIO_NUM_NC;
    buscfg.sclk_io_num = ST7735_CK_GPIO;
    buscfg.quadwp_io_num = GPIO_NUM_NC;
    buscfg.quadhd_io_num = GPIO_NUM_NC;
    buscfg.max_transfer_sz = SPI_BLACK_SIZE;
    ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
}

void initializeLcd() {
    esp_lcd_panel_io_handle_t panel_io = NULL;
    panel_handle=NULL;
    // 液晶屏控制IO初始化
    ESP_LOGI(TAG, "Install panel IO");
    esp_lcd_panel_io_spi_config_t io_config = {};

    io_config.cs_gpio_num = PIN_NUM_CS;
    io_config.dc_gpio_num = PIN_NUM_DC;
    io_config.spi_mode = 0;
    io_config.pclk_hz = 40 * 1000 * 1000;
    io_config.trans_queue_depth = 10;
    io_config.lcd_cmd_bits = 8;
    io_config.lcd_param_bits = 8;
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI2_HOST, &io_config, &panel_io));

    // 初始化液晶屏驱动芯片
    ESP_LOGI(TAG, "Install LCD driver");
    esp_lcd_panel_dev_config_t panel_config = {};
    panel_config.reset_gpio_num = PIN_NUM_RST;
    panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB;
    panel_config.bits_per_pixel = 16;
    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel_handle));

    esp_lcd_panel_reset(panel_handle);

    esp_lcd_panel_init(panel_handle);
    esp_lcd_panel_invert_color(panel_handle, false);
    esp_lcd_panel_swap_xy(panel_handle, false);
    esp_lcd_panel_mirror(panel_handle, true, true);
    
    esp_lcd_panel_disp_on_off(panel_handle, true);

    // clear screen prevent random dot on screen
    memset(rgb565_buffer,0,decoded_size);
    esp_lcd_panel_draw_bitmap(panel_handle, 
        0, 0, ST7735_WIDTH, ST7735_HEIGHT, 
        rgb565_buffer);
    
    /*
    // 看起来有专门的port代码对应lvgl在esp32上的各种设置
    // label字体也正常了，但要求内存偏多
    lvgl_port_cfg_t port_cfg = ESP_LVGL_PORT_INIT_CONFIG();
    port_cfg.task_priority = 1;
    port_cfg.timer_period_ms = 50;
    lvgl_port_init(&port_cfg);

    ESP_LOGI(TAG, "Adding LCD screen");
    const lvgl_port_display_cfg_t display_cfg = {
        .io_handle = panel_io,
        .panel_handle = panel_handle,
        .control_handle = NULL,
        .buffer_size = (uint32_t)(ST7735_WIDTH * 10),
        .double_buffer = false,
        .trans_size = 0,
        .hres = (uint32_t)(ST7735_WIDTH),
        .vres = (uint32_t)(ST7735_HEIGHT),
        .monochrome = false,
        .rotation = {
            .swap_xy = false,
            .mirror_x = true,
            .mirror_y = true,
        },
        .color_format = LV_COLOR_FORMAT_RGB565,
        .flags = {
            .buff_dma = 1,
            .buff_spiram = 0,
            .sw_rotate = 0,
            .swap_bytes = 1,
            .full_refresh = 0,
            .direct_mode = 0,
        },
    };

    lv_display_t *display_ = lvgl_port_add_disp(&display_cfg);
    */
}

static void tick_inc_cb(void *arg) {
    lv_tick_inc(1);
}
void initializeLVGL(){
    // 初始化LVGL
    lv_init();

    // Create display buffer
    static lv_color_t *buf1 = NULL;
    static lv_draw_buf_t draw_buf1;
    uint32_t buf_pixels = LCD_H_RES * BUF_HEIGHT;

    buf1 = (lv_color_t*)heap_caps_malloc(buf_pixels * sizeof(lv_color_t), 
        MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
    assert(buf1);

    // 正确初始化 draw buffer
    lv_draw_buf_init(&draw_buf1,
                     LCD_H_RES,                   // 宽度
                     BUF_HEIGHT,                  // 高度
                     LV_COLOR_FORMAT_NATIVE,      // 色彩格式
                     LCD_H_RES,                   // stride = 每行像素数
                     buf1,                        // 指向 buffer
                     buf_pixels);                 // 总像素数

    disp = lv_display_create(ST7735_WIDTH, ST7735_HEIGHT);

    lv_display_set_flush_cb(disp, lvgl_flush_cb);
    lv_display_set_draw_buffers(disp, &draw_buf1, NULL);  // 单缓冲
    lv_display_set_user_data(disp, panel_handle);
    // 设置显示为默认
    lv_display_set_default(disp);

    // Start tick timer
    const esp_timer_create_args_t lvgl_tick_timer_args = {
        .callback = &tick_inc_cb,
        .name = "lvgl_tick"
    };
    esp_timer_handle_t lvgl_tick_timer;
    esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer);
    esp_timer_start_periodic(lvgl_tick_timer, 1000); // 1ms=1000us,此处是us为单位
    ESP_LOGI(TAG, "init LVGL finish.");
}
void settingUI(){
    // for test
    // for (int i = 0; i < ST7735_HEIGHT*ST7735_WIDTH; i++) {
    //     rgb565_buffer[i] = 0xF800; // 红色 (RGB565)
    // }
    // memset(rgb565_buffer,0,decoded_size);

    lv_obj_t * screen = lv_screen_active();
    lv_obj_set_style_text_font(screen, &font_puhui_14_1, 0);

    // 创建 LVGL 图片对象
    img_dsc.header.cf = LV_COLOR_FORMAT_RGB565;
    img_dsc.data = (uint8_t *)rgb565_buffer;
    img_dsc.header.w = ST7735_WIDTH;
    img_dsc.header.h = ST7735_HEIGHT;
    img_dsc.data_size = decoded_size;

    //创建图片控件
    img = lv_image_create(screen /*lv_screen_active()*/);
    lv_image_set_src(img, &img_dsc);
    lv_obj_center(img);

    // 创建一个按钮或标签
    // 测试创建文字标签是可以工作的
    label_date = lv_label_create(screen);
    label_week = lv_label_create(screen);
    label_time = lv_label_create(screen);
    // 使用字体，需要先在sdkconfig中打开，比如：CONFIG_LV_FONT_MONTSERRAT_20=y
    lv_obj_set_style_text_font(label_date, &lv_font_montserrat_14, LV_PART_MAIN);
    lv_obj_set_style_text_font(label_week, &lv_font_montserrat_14, LV_PART_MAIN);
    lv_obj_set_style_text_font(label_time, &lv_font_montserrat_20, LV_PART_MAIN);
    lv_obj_set_flex_grow(label_date, 1);
    lv_label_set_text(label_date, "");
    lv_label_set_text(label_time, "");
    lv_label_set_text(label_week, "");
    /*
    char stime[64];
    get_current_date(stime,64);
    lv_label_set_text(label_date, stime);
    get_current_time(stime,64);
    lv_label_set_text(label_time, stime);
    get_current_week(stime,64);
    lv_label_set_text(label_week, stime);
    */
    // menuconfig中LVGL颜色设置要选择RGB565,同LCD吻合
    lv_obj_set_style_text_color(label_date, 
            lv_color_make(255,255,255), LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(label_week, 
            lv_color_make(255,0,200), LV_STATE_DEFAULT);
    lv_obj_set_style_text_color(label_time, 
            lv_color_make(255,0,0), LV_STATE_DEFAULT);
    // lv_obj_center(label);
    lv_obj_align(label_date, LV_ALIGN_BOTTOM_LEFT, 0, 0);
    lv_obj_align(label_week, LV_ALIGN_BOTTOM_LEFT, 0, -19);
    lv_obj_align(label_time, LV_ALIGN_BOTTOM_LEFT, 40,-16);

    lv_obj_t *label_tmp = lv_label_create(screen);
    lv_obj_set_style_text_color(label_tmp, 
            lv_color_make(255,255,255), LV_STATE_DEFAULT);
    lv_obj_align(label_tmp, LV_ALIGN_TOP_LEFT, 0, 0);
    lv_label_set_text(label_tmp, "人生如逆旅\n我亦是行人");

    ESP_LOGI(TAG, "init UI finish.");
}
void showMsg(const char *msg){
    lv_label_set_text(label_date, msg);
}
void decode_jpeg_to_rgb565(uint8_t *jpg_data, size_t jpg_size) {
    esp_jpeg_image_cfg_t jpeg_cfg = {
        .indata = jpg_data,
        .indata_size = jpg_size,
        .outbuf = (uint8_t *)rgb565_buffer,
        .outbuf_size = decoded_size,
        .out_format = JPEG_IMAGE_FORMAT_RGB565,
        .out_scale = JPEG_IMAGE_SCALE_0,
        .flags = {
            .swap_color_bytes = 0,
            // .swap_color_bytes = 1,
        }
    };
    // int32_t len = decoded_size;
    // for (int i = 0; i < len; i+=2) {
    //     uint8_t c = rgb565_buffer[i];
    //     rgb565_buffer[i]=rgb565_buffer[i+1];
    //     rgb565_buffer[+1] = c;
    // }

    esp_jpeg_image_output_t outimg;
    // memset(rgb565_buffer,0,decoded_size);

    esp_jpeg_decode(&jpeg_cfg, &outimg);
    ESP_LOGI(TAG, "JPEG image decoded! Size of the decoded image is: %dpx x %dpx", outimg.width, outimg.height);

    // use esp_lcd old method show pic
    // its work,but lvgl not work
    // esp_lcd_panel_draw_bitmap(panel_handle, 
    //     0, 0, ST7735_WIDTH, ST7735_HEIGHT, 
    //     rgb565_buffer);
    needRenderPhoto=true;
}
void renderPhoto(){
    if (!needRenderPhoto) return;
    // show in lvgl
    // 创建图片控件
    lv_image_set_src(img, &img_dsc);
    needRenderPhoto=false;

    char sdate[15],sweek[5],stime[10];
    get_current_time(sdate,15,sweek,5,stime,10);

    lv_label_set_text(label_date, sdate);
    lv_label_set_text(label_time, stime);
    lv_label_set_text(label_week, sweek);
    // for (int i = 0; i < ST7735_HEIGHT*ST7735_WIDTH; i++) {
    //     rgb565_buffer[i] = 0xF800; // 红色 (RGB565)
    // }

}
